<template></template>
<script>
import * as Three from "three";
import TWEEN from "@tweenjs/tween.js";
import { SkeletonUtils } from "../utils/SkeletonUtils";

export default {
  name: "person",
  props: {
    code: { type: String },
    name: { type: String },
    avatar: { type: String },
    scale: { type: Array },
    posId: { type: Number },
    location: { type: Array }, // [x, y, z]
    models: { type: Object },
    type: { type: String },
    historyLocations: { type: Array, default: _ => [] }
  },
  data() {
    return {
      current: null,
      walkModel: null,
      mixer: null,
      idleAction: null,
      walkAction: null,
      lastLocation: null,
      walking: false,
      timer: null,
      currLocation: [],
      myTween: null,
      timerPosition: null,
      currentHLMesh: null,
      lastPosId: 0,
      likeLineGroup: null,
      defaultWidth: 0.1
    };
  },
  watch: {
    currLocation() {
      if (!this.walking) {
        this.updateLocationAnimation();
      }
    },
    historyLocations() {
      this.drawHistoryLocations(this.historyLocations);
    }
  },
  mounted() {
    this.currLocation.push(this.location);
    this.lastPosId = this.posId;
    this.intermittent();
    // 定时获取人当前位置坐标
    // this.timerPosition = setInterval(
    //   _ => this.loadPersonCurrentPositions(),
    //   1000
    // );
  },
  methods: {
    // 人的行走轨迹为间断性的,相邻两个坐标点之间有一定的距离,此时需要使用动画,后台数据返回为多个坐标
    intermittent() {
      this.current = new Three.Group();
      let position = this.currLocation.shift();
      this.initPerson(position);
      this.lastLocation = position;
      this.updateLocationAnimation();
    },
    initPerson(position) {
      let model = this.models.walkModel[this.type];
      if (model) {
        let walkModel = SkeletonUtils.clone(model);
        walkModel.name = "person-" + this.code;
        this.walkModel = walkModel;
        this.current.add(this.walkModel);
        this.current.position.set(position[0], position[1], position[2]);
        let mixer = new Three.AnimationMixer(this.walkModel);
        let idleAction = mixer.clipAction(
          this.models.walkModel[this.type].idleAnimation
        );
        let walkAction = mixer.clipAction(
          this.models.walkModel[this.type].walkAnimation
        );
        this.mixer = mixer;
        this.idleAction = idleAction;
        this.walkAction = walkAction;
        idleAction.play();
        walkAction.play();
        this.setWeight(idleAction, 1);
        this.setWeight(walkAction, 0);

        this.$parent.scene.add(this.current);
        this.$parent.persons.push(this);
      } else {
        console.log("类型", this.type, "没有对应的3D模型");
      }
    },
    // 更新人的位置，由于后台返回的是一系列间断的坐标点，所以需要使用TWEENJS动画，初始时数组中第一个值为当前位置，依次从第二个值行走到最后一个点，行走过程中可能会更新新的位置到数组中
    updateLocationAnimation() {
      if (this.currLocation.length <= 0 || !this.current) {
        return;
      }
      if (!this.walking) {
        this.walking = true;
      }
      this.setWeight(this.idleAction, 0);
      this.setWeight(this.walkAction, 1);
      let fromPosition = this.lastLocation;
      let toPosition = (this.lastLocation = this.currLocation.shift());
      let dist = this.distance(fromPosition, toPosition);
      this.myTween = new TWEEN.Tween(fromPosition)
        .to(toPosition, (dist / 2) * 1000)
        .onUpdate(_ => {
          this.current.lookAt(
            fromPosition[0],
            fromPosition[1],
            fromPosition[2]
          );
          // this.current.rotation.y += Math.PI;
          this.current.position.set(
            fromPosition[0],
            fromPosition[1],
            fromPosition[2]
          );
        })
        .onComplete(_ => {
          this.walking = false;
          this.setWeight(this.idleAction, 1);
          this.setWeight(this.walkAction, 0);
          this.updateLocationAnimation();
        })
        .start();
    },
    setWeight(action, weight) {
      action.enabled = true;
      action.setEffectiveTimeScale(1);
      action.setEffectiveWeight(weight);
    },
    distance(point1, point2) {
      return Math.sqrt(
        Math.pow(point1[0] - point2[0], 2) +
          Math.pow(point1[1] - point2[1], 2) +
          Math.pow(point1[2] - point2[2], 2)
      );
    },
    drawHistoryLocations(historyLocations) {
      let points = historyLocations, pt;
      let likeLine;
      if (points && points.length > 0) {
        this.likeLineGroup = new Three.Group(), material = new Three.MeshBasicMaterial({ color: 0xff0000 });
        let len = points.length;
        for (let i = 0; i < len - 1; i++) {
          let p1 = points[i],
            p2 = points[i + 1];
          let geometry, distance, position;
          if (p1[0] !== p2[0]) {
            distance = Math.abs(p2[0] - p1[0]);
            geometry = new Three.BoxGeometry(
              distance,
              this.defaultWidth,
              this.defaultWidth
            );
            if (p1[0] > p2[0]) {
              pt = p2;
            } else {
              pt = p1;
            }
            position = {
              x: pt[0] + distance / 2,
              y: pt[1] + 1,
              z: pt[2]
            };
          } else if (p1[1] !== p2[1]) {
            distance = Math.abs(p2[1] - p1[1]);
            geometry = new Three.BoxGeometry(
              this.defaultWidth,
              distance,
              this.defaultWidth
            );
            if (p1[1] > p2[1]) {
              pt = p2;
            } else {
              pt = p1;
            }
            position = {
              x: pt[0],
              y: pt[1] + distance / 2,
              z: pt[2]
            };
          } else if (p1[2] !== p2[2]) {
            distance = Math.abs(p2[2] - p1[2]);
            geometry = new Three.BoxGeometry(
              this.defaultWidth,
              this.defaultWidth,
              distance
            );
            if (p1[2] > p2[2]) {
              pt = p2;
            } else {
              pt = p1;
            }
            position = {
              x: pt[0],
              y: pt[1] + 1,
              z: pt[2] + distance / 2
            };
          } else {
            continue;
          }
          likeLine = new Three.Mesh(
            geometry,
            material
          );

          likeLine.position.x = position.x;
          likeLine.position.y = position.y;
          likeLine.position.z = position.z;

          this.likeLineGroup.add(likeLine);
        }
        this.$parent.scene.add(this.likeLineGroup);
      } else if (this.likeLineGroup !== null) {
        this.$parent.scene.remove(this.likeLineGroup);
      }
    }
  },
  beforeDestroy() {
    console.log("player destroy");
    if (this.myTween) {
      TWEEN.remove(this.myTween);
    }
    delete this.myTween;
    clearInterval(this.timerPosition);
    this.timerPosition = null;
    if (this.$parent) {
      this.$parent.persons.splice(this.$parent.persons.indexOf(this), 1);
    }
    if (this.$parent.scene) {
      this.$parent.scene.remove(this.current);
    }
    delete this.mixer;
    delete this.current;
  }
};
</script>

<style>
.person {
}
</style>